跳到主要内容

Shell 接受参数与接受信号

传递参数给 Script

可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n

n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……

实例:

以下实例我们向脚本传递三个参数,并分别输出,其中 $0 为执行的文件名(包含文件路径):

#!/bin/bash

echo "Shell 传递参数实例!";
echo "执行的文件名: $0";
echo "第一个参数为: $1";
echo "第二个参数为: $2";
echo "第三个参数为: $3";

为脚本设置可执行权限,并执行脚本,输出结果如下所示:

$ chmod +x test.sh 
$ ./test.sh 1 2 3
Shell 传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3

一般校验参数是否传递完毕可以只判断最后一个参数是否为空就行了

if [ "$3" == "" ]; then
echo "Missing parameter!";
exit 1;
fi

trap 命令接收信号

trap 是一个可以设置接收信号类型,然后执行你给出的命令的命令。

这种类似回调函数和 Go 语言中 defer 一样的用法。具体的用法就是:

trap command signal

其中中间的是我们需要执行的命令,最后的是我们想要监听的信号(这里就不列出了所有的信号,可以 trap -l 查看),这样以后如果需要在脚本执行完毕后加 log,就可以这么操作。

例子:

trap "echo 'xxoo' " HUP INT QUIT TSTP

执行完上面命令,每次在控制台 Ctrl+c 都会打印 "xx00",这样我们可以做到屏蔽信号的作用,恢复到原样,继续执行下面的命令

特殊的自带变量

另外,还有几个特殊字符用来处理参数:

$#  # 传递到脚本的参数个数
$* # 以一个单字符串显示所有向脚本传递的参数。如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$$ # 脚本运行的当前进程ID号
$! # 后台运行的最后一个进程的ID号
$@ # 与$*相同,但是使用时加引号,并在引号中返回每个参数。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$- # 显示Shell使用的当前选项,与set命令功能相同。
$? # 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

使用例:

#!/bin/bash

echo "Shell 传递参数实例!";
echo "第一个参数为: $1";

echo "参数个数为: $#";
echo "传递的参数作为一个字符串显示: $*";

执行脚本,输出结果如下所示:

$ chmod +x test.sh 
$ ./test.sh 1 2 3
Shell 传递参数实例!
第一个参数为:1
参数个数为:3
传递的参数作为一个字符串显示:1 2 3

移动变量 ⭐

有时候编写脚本并不知道用户可能会输入多少个参数,但是又需要处理这些参数,所以这种时候就可以使用 shift 命令对这些参数进行漂移

在使用 shift 命令时,默认情况下它会将每个参数变量向左移动一个位置,所以

#!/bin/bash

shift
# 默认 1 是代表第一个参数,这里漂移后读取的是第二个参数
echo "$1"

output

$ ./main.sh 1 2                 
2
$

上面这样看起来似乎很没有用,但是配合上 while 循环就非常好用了

#!/bin/bash

echo
count=1
while [ -n "$1" ]
do
echo "Parameter #$count = $1"
count=$((count + 1))
shift
done

output

$ ./main.sh 1 2 3 4

Parameter #1 = 1
Parameter #2 = 2
Parameter #3 = 3
Parameter #4 = 4

处理选项

平时可以看到一些命令后面是可以携带一些命令行选项的,实际上写起来也很简单

#!/bin/bash

echo
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) echo "Found the -b option" ;;
-c) echo "Found the -c option" ;;
*) echo "$1 is not an option" ;;
esac
shift
done

output

$ ./main.sh -a -b -c -d

Found the -a option
Found the -b option
Found the -c option
-d is not an option
$

同时使用选项和参数

在 shell 脚本中存在同时使用选项和参数的情况。Linux 中处理这个问题的标准方式是用特殊字符来将二者分开,该字符会告诉脚本何时选项结束以及普通参数何时开始。 对 Linux 来说,这个特殊字符是双破折线(--)。shell 会用双破折线来表明选项列表结束。在双破折线之后,脚本就可以放心地将剩下的命令行参数当作参数,而不是选项来处理了。

要检查双破折线,只要在 case 语句中加一项就行了。

#!/bin/bash

echo
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) echo "Found the -b option" ;;
-c) echo "Found the -c option" ;;
--) shift
break ;;
*) echo "$1 is not an option" ;;
esac
shift
done

count=1
for param in "$@"
do
echo "Parameter #$count: $param"
count=$((count + 1))
done
$ ./main.sh -a -b -c -d -- a b c

Found the -a option
Found the -b option
Found the -c option
-d is not an option
Parameter #1: a
Parameter #2: b
Parameter #3: c
$

处理带值的选项

有些选项会带上一个额外的参数值。处理起来也很简单,读取多少个参数就 shift 多少次就行了,如下的 -b 选项需要读取一个参数,那么左移一次就行了

#!/bin/bash

echo
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option";;
-b) param="$2"
echo "Found the -b option, with parameter value $param"
shift ;;
-c) echo "Found the -c option";;
--) shift
break ;;
*) echo "$1 is not an option";;
esac
shift
done
#
count=1
for param in "$@"
do
echo "Parameter #$count: $param"
count=$((count + 1))
done

output

$ ./main.sh -a -b test1 -d
Found the -a option
Found the -b option, with parameter value test1
-d is not an option
$

合并选项 getopts

平时看到的脚本都支持合并选项的功能,如下:

$ ./main -abc

这种情况可以使用 getopts 命令来处理,getopts 命令可以接受一系列任意形式的命令行选项和参数,并自动将它们转换成适当的格式。它的命令格式如下:

getopts optstring variable

每次调用它时,它一次只处理命令行上检测到的一个参数。处理完所有的参数后,它会退出并返回一个大于 0 的退出状态码。

这让它非常适合用于解析命令行所有参数的循环中

#!/bin/bash
# simple demonstration of the getopts command
#
echo
while getopts :ab:c opt
do
case "$opt" in
a) echo "Found the -a option" ;;
b) echo "Found the -b option, with value $OPTARG";;
c) echo "Found the -c option" ;;
*) echo "Unknown option: $opt";;
esac
done
$ ./main.sh -ab test1 -c
Found the -a option
Found the -b option, with value test1
Found the -c option
$

有效的选项字母都会列在 optstring 中,如果选项字母要求有个参数值,就加一个冒号。要去掉错误消息的话,可以在 optstring 之前加一个冒号。getopts 命令将当前参数保存在命令行中定义的 variable 中。